/**
 * @Description:博客园地址：https://www.cnblogs.com/zumengjie/
 * @author:顶风少年
 * @date: 2021年4月1日 下午9:27:45
 */
package datang.dtdb.builder.xml;

import java.io.InputStream;
import java.util.Properties;

import javax.sql.DataSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import datang.dtdb.builder.BaseBuilder;
import datang.dtdb.datasource.DataSourceFactory;
import datang.dtdb.exceptions.TypeException;
import datang.dtdb.exceptions.XMLParserException;
import datang.dtdb.io.Resources;
import datang.dtdb.mapping.Environment;
import datang.dtdb.parsing.XPathParser;
import datang.dtdb.session.Configuration;
import datang.dtdb.transaction.TransactionFactory;
import datang.dtdb.type.TypeAilasRegistry;

/**
 * 解析步骤入口
 */
public class XMLConfigBuilder extends BaseBuilder {

	private Document sqlMapConfig;

	// TODO 完成解析
	/**
	 * 解析SqlMapConfig构造器
	 */
	public XMLConfigBuilder(InputStream resource) {
		super(new Configuration());
		sqlMapConfig = XPathParser.document(resource);
	}

	/**
	 * 返回Configuration
	 */
	public Configuration parse() {
		parseConfiguration(XPathParser.rootElement(sqlMapConfig));
		return configuration;
	}

	/**
	 * XML中所有的一级标签解析入口
	 */
	private void parseConfiguration(Element rootElement) {
		environmentsElement(XPathParser.singleEleByTagName(rootElement, "environments"));
		mapperElement(XPathParser.singleEleByTagName(rootElement, "mappers"));
	}

	/**
	 * 处理mappers标签
	 * */
	private void mapperElement(Node mappers) {
		NodeList nodes = XPathParser.listEle(mappers);
		for (int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);
			String nodeName = node.getNodeName();
			if (nodeName.equals("package")) {
				// 处理package
			} else if (nodeName.equals("mapper")) {
				String resource = XPathParser.eleAttr(node, "resource");
				String url = XPathParser.eleAttr(node, "url");
				String mapperClass = XPathParser.eleAttr(node, "class");
				// 解析resource下的mapper
				if (resource != null && url == null && mapperClass == null) {
					InputStream inputStream = Resources.getResourceAsStream(resource);
					XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(inputStream, configuration);
					xmlMapperBuilder.parse();
				}
			}
		}
	}

	/**
	 * 解析数据源运行环境
	 */
	private void environmentsElement(Node environments) {
		if (environments == null) {
			throw new XMLParserException("environments标签不存在");
		}
		String defaultEnv = XPathParser.eleAttr(environments, "default");
		if (defaultEnv == null) {
			throw new XMLParserException("environments缺少default属性");
		}
		Environment environment = null;
		NodeList environmentList = XPathParser.listEleByTagName(environments, "environment");
		for (int i = 0; i < environmentList.getLength(); i++) {
			Node currentEnvironment = environmentList.item(i);
			String envId = XPathParser.eleAttr(currentEnvironment, "id");
			if (envId == null) {
				throw new XMLParserException("environment[" + i + "]缺少id属性");
			}
			if (defaultEnv.equals(envId)) {
				Node transactionManagerNode = XPathParser.singleEleByTagName(currentEnvironment, "transactionManager");
				TransactionFactory transactionFactory = transactionManagerElement(transactionManagerNode);
				Node dataSourceNode = XPathParser.singleEleByTagName(currentEnvironment, "dataSource");
				DataSource dataSource = dataSourceElement(dataSourceNode);
				environment = new Environment(envId, dataSource, transactionFactory);
			}
		}
		if (environment == null) {
			throw new XMLParserException("匹配不到" + defaultEnv);
		}
		configuration.setEnvironment(environment);
	}

	/**
	 * 获取事务管理器
	 */
	private TransactionFactory transactionManagerElement(Node transactionManagerNode) {
		if (transactionManagerNode == null) {
			throw new XMLParserException("transactionManager节点不存在");
		}
		String tranType = XPathParser.eleAttr(transactionManagerNode, "type");
		if (tranType == null) {
			throw new XMLParserException("transactionManager标签缺少type");
		}
		try {
			TransactionFactory transacionFactory = (TransactionFactory) resolveAlias(tranType).newInstance();
			Properties properties = XPathParser.eleProperties(transactionManagerNode);
			transacionFactory.setProperties(properties);
			return transacionFactory;
		} catch (Exception e) {
			throw new TypeException("获取事务管理器" + tranType + "失败", e);

		}
	}

	/**
	 * 获取连接池
	 */
	private DataSource dataSourceElement(Node dataSourceNode) {
		if (dataSourceNode == null) {
			throw new XMLParserException("dataSource节点不存在");
		}
		String dataSourceType = XPathParser.eleAttr(dataSourceNode, "type");
		if (dataSourceType == null) {
			throw new XMLParserException("dataSource标签缺少type");
		}
		try {
			DataSourceFactory dataSourceFactory = (DataSourceFactory) resolveAlias(dataSourceType).newInstance();
			Properties properties = XPathParser.eleProperties(dataSourceNode);
			dataSourceFactory.setProperties(properties);
			return dataSourceFactory.getDataSource();
		} catch (Exception e) {
			throw new TypeException("获取连接池" + dataSourceType + "失败", e);
		}
	}

}
